package glossos;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import glossos.tree.FrequencyTree;
import glossos.tree.factory.SimpleNodeFactory;
import glossos.tree.snapshot.InMemoryInsertionSnapshot;
import glossos.tree.snapshot.InsertionSnapshot;
import glossos.tree.snapshot.NodeRepository;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.junit.Test;
import static org.mockito.Mockito.*;

public class FrequencyTreeTestCase {
    //TODO Mock collaborators
	FrequencyTree frequencyTree;
	
	NodeRepository nodeRepository = mock(NodeRepository.class);

    @Test
    public void calculateMostFrequentSequences() throws Exception {
        frequencyTree = new FrequencyTree(createSnapshot(2), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "abc", "xyz", "abc", "def"));
        frequencyTree.update(Arrays.asList("abc"));

        assertThat(frequencyTree.mostFrequentSequence(1), is("abc"));
        assertThat(frequencyTree.mostFrequentSequence(2), is("abc def"));
    }

    @Test
    public void noSequenceWithTheSpecifiedSize() {
        frequencyTree = new FrequencyTree(createSnapshot(6), new SimpleNodeFactory());
        frequencyTree.update(Arrays.asList("abc", "def", "ghi", "ghi"));

        assertThat(frequencyTree.mostFrequentSequence(5), is(""));
    }

    @Test
    public void calculateFrequencyOfSingleWords() {
        frequencyTree = new FrequencyTree(createSnapshot(2), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "abc", "xyz", "abc", "def"));
        frequencyTree.update(Arrays.asList("abc"));

        assertThat(frequencyTree.frequency("abc"), is(4));
        assertThat(frequencyTree.frequency("def"), is(2));
        assertThat(frequencyTree.frequency("xyz"), is(1));
        assertThat(frequencyTree.frequency("pqp"), is(0));
        assertThat(frequencyTree.frequency(""), is(0));
    }

    @Test
    public void calculateFrequencyOfPairs() throws Exception {
        frequencyTree = new FrequencyTree(createSnapshot(2), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "abc", "xyz", "abc", "def"));
        frequencyTree.update(Arrays.asList("abc"));

        assertThat(frequencyTree.frequency("abc def"), is(2));
        assertThat(frequencyTree.frequency("abc xyz"), is(1));
        assertThat(frequencyTree.frequency("def xyz"), is(0));
    }

    @Test
    public void matchingSequencesForLiteralsOnly() {
        frequencyTree = new FrequencyTree(createSnapshot(3), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "ghi", "abc", "def", "ghi", "abc", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "def"));

        String[] pattern = new String[]{"abc", "def", "xyz"};
        List<String> result = frequencyTree.sequencesMatching(pattern);
        List<String> expected = Arrays.asList("abc def xyz");

		assertThat(result, is(expected));
    }

    @Test
    public void nonMatchingSequencesForLiteralsOnly() {
        frequencyTree = new FrequencyTree(createSnapshot(3), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "ghi", "abc", "def", "ghi", "abc", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "def"));

        String[] pattern = new String[]{"abc", "def", "foo"};
        List<String> result = frequencyTree.sequencesMatching(pattern);
        List<String> expected = Collections.emptyList();

		assertThat(result, is(expected));
    }

    @Test
    public void matchingSequencesForVariableAtTheEnd() {
        frequencyTree = new FrequencyTree(createSnapshot(3), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "ghi", "abc", "def", "ghi", "abc", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "def"));

        String[] pattern = new String[]{"abc", "def", "$"};
        List<String> result = frequencyTree.sequencesMatching(pattern);
        List<String> expected = Arrays.asList("abc def ghi", "abc def xyz");

		assertThat(result, is(expected));
    }

    @Test
    public void matchingSequencesForVariableAtTheBegining() {
        frequencyTree = new FrequencyTree(createSnapshot(3), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "xyz", "abc", "def", "ghi", "abc", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "def", "ghi"));
        frequencyTree.update(Arrays.asList("foo", "def", "xyz"));

        String[] pattern = new String[]{"$", "def", "xyz"};
        List<String> result = frequencyTree.sequencesMatching(pattern);
        List<String> expected = Arrays.asList("abc def xyz", "foo def xyz");

		assertThat(result, is(expected));
    }

    @Test
    public void matchingSequencesForVariableInTheMiddle() {
        frequencyTree = new FrequencyTree(createSnapshot(3), new SimpleNodeFactory());
        frequencyTree.start();
        frequencyTree.update(Arrays.asList("abc", "def", "ghi", "abc", "def", "ghi", "abc", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "def"));
        frequencyTree.update(Arrays.asList("foo", "def", "xyz"));
        frequencyTree.update(Arrays.asList("abc", "burger", "ghi"));

        String[] pattern = new String[]{"abc", "$", "ghi"};
        List<String> result = frequencyTree.sequencesMatching(pattern);
        List<String> expected = Arrays.asList("abc def ghi", "abc burger ghi");

		assertThat(result, is(expected));
    }


    private InsertionSnapshot createSnapshot(int height) {
        InMemoryInsertionSnapshot snapshot = new InMemoryInsertionSnapshot(height, new SimpleNodeFactory());
        snapshot.setNodeRepository(nodeRepository);
		return snapshot;
    }
}
